package org.nahtanoj.driveutils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.logging.Logger;

import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.drive.DriveScopes;

public class Authenticator {
	private static String CLIENT_ID = "934792418145-17idd0v23timnkp10n0d46t1c2r0qh0e.apps.googleusercontent.com";
	private static String CLIENT_SECRET = "45sTgT90a0vE4KzzcCDsYfj9";
	private static GoogleCredential credential = null;
	private static HttpTransport httpTransport = new NetHttpTransport();
	private static JsonFactory jsonFactory = new JacksonFactory();
	private static final Logger log = Logger.getLogger(Authenticator.class.getName());
	private static String REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";
	private final File refreshTokenFile = new File("refreshToken.txt");

	public Authenticator() {
		// If access token is not null check expiry and use
		// If null or expired
		// If refresh token file exists, and is not empty
		// Load and use it and store access token
		// If not there or empty then prompt for manual confirmation
		if (Authenticator.credential == null) {
			if (getRefreshToken() == null) {
				getManualAuth();
			}
		} else {
			// Check expiry
			if (Authenticator.credential.getExpiresInSeconds() < 60) {
				if (getRefreshToken() == null) {
					getManualAuth();
				}
			}
		}
	}

	public GoogleCredential getCredential() {
		return Authenticator.credential;
	}

	private void getManualAuth() {
		try {
			GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
					httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET,
					Arrays.asList(DriveScopes.DRIVE)).setAccessType("offline")
					.setApprovalPrompt("force").build();
			System.out.println("Please visit:" + flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).toString());
			System.out.print("Enter code:");
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			String code =  br.readLine();

			GoogleTokenResponse response = flow.newTokenRequest(code)
					.setRedirectUri(REDIRECT_URI).execute();
			Authenticator.credential = new GoogleCredential().setAccessToken(response.getAccessToken());
			FileWriter f = new FileWriter(refreshTokenFile);
			f.write(response.getRefreshToken());
			f.close();
		} catch (Exception e) {
			log.severe(e.getMessage());
		}
	}

	private String getRefreshToken() {
		String refreshToken = null;
		try {
			if (refreshTokenFile.exists() &&
					refreshTokenFile.isFile() &&
					refreshTokenFile.canRead() &&
					refreshTokenFile.length() > 10) {
				BufferedReader br = new BufferedReader(
									new InputStreamReader(
									new FileInputStream(refreshTokenFile)));
				refreshToken = br.readLine();
				br.close();
				Authenticator.credential = new GoogleCredential.Builder()
				.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
				.setJsonFactory(jsonFactory)
				.setTransport(httpTransport).build();
				Authenticator.credential.setRefreshToken(refreshToken);
				Authenticator.credential.refreshToken();
			}
		} catch (Exception e) {
			log.severe(e.getMessage());
		}
		return refreshToken;
	}
}
